package top.ahzy.seobench.websocket;

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.ahzy.seobench.consts.MessageSocketConst;
import top.ahzy.seobench.model.dto.MessageDto;
import top.ahzy.seobench.sparkLite.SparkService;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 前后端交互的类实现消息的接收推送(自己发送给自己)
 *
 * @author ahzy
 * @ServerEndpoint(value = "/messageSocket/123") 前端通过此URI和后端交互，建立连接
 */
@Slf4j
@Component
@ServerEndpoint(value = "/messageSocket/{userId}", configurator = AuthMessageSocket.class)
public class MessageSocket {
    /**
     * String : 用户ID
     * Session： 回话
     */
    public static Map<String, Session> sessionMap = new ConcurrentHashMap<String, Session>();

    /**
     * onOpen是当用户发起连接时，会生成一个用户的Session 注意此Session是 javax.websocket.Session;
     * 然后我们用userId作为Key Session作为Vaule存入Map中暂存起来
     *
     * @param userId
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("userId") String userId, Session session) {
        log.info("====>WebSocketService onOpen: " + userId);
        if (sessionMap == null) {
            sessionMap = new ConcurrentHashMap<String, Session>();
        }
        sessionMap.put(userId, session);
    }

    /**
     * onClose 是用户关闭聊天窗时，将用户session移除
     *
     * @param userId
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId) {
        log.info("====>WebSocketService OnClose: " + userId);
        SparkService.sparkWebSocketMap.remove(userId);
        sessionMap.remove(userId);
    }

    /**
     * onMessage 实现聊天功能， message是前端传来的JSON字符串。其中含有MessageVo里的信息。根据vo实现点对点/广播聊天。
     *
     * @param message
     */
    @OnMessage
    public void onMessage(@PathParam("userId") String userId, String message) {
        MessageDto msg = JSON.parseObject(message, MessageDto.class);
        msg.setUserId(userId);
        log.info("====>msg: " + JSON.toJSONString(msg));
        msg.setType(MessageSocketConst.MESSAGE_TYPE_CHAT);
        if (msg.getComsumerId() == null || msg.getComsumerId().isEmpty()) {
            // 广播
            toAllNotMe(msg);
        } else {
            // 点对点
            sendMsg(msg);
        }
    }

    /**
     * 当出现异常时候自动调用该方法。
     *
     * @param t
     */
    @OnError
    public void error(Throwable t) {
        t.printStackTrace();
    }

    /**
     * 点对点
     * session.getAsyncRemote().sendText(message); 即向目标session发送消息。
     */
    public Boolean sendMsg(MessageDto msg) {
        Session consumerSession = sessionMap.get(msg.getComsumerId());
        if (consumerSession == null) {
            log.info("消息消费者不存在");
            return Boolean.FALSE;
        }
        consumerSession.getAsyncRemote().sendText(JSON.toJSONString(msg));
        return Boolean.TRUE;

    }


    /**
     * 广播
     * 向所有session发送消息
     */
    public Boolean toAll(String message) {
        for (Session session : sessionMap.values()) {
            session.getAsyncRemote().sendText(message);
        }
        return Boolean.TRUE;
    }

    /**
     * 广播并排除自己
     * 向所有session发送消息
     */
    public void toAllNotMe(MessageDto msg) {
        for (Session session : sessionMap.values()) {
            if (!session.getRequestParameterMap().get("userId").get(0).equals(msg.getUserId())) {
                session.getAsyncRemote().sendText(JSON.toJSONString(msg));
            }
        }
    }

}
